#!/usr/bin/python2.4


import _mysql_exceptions
import signal
import threading
import time
import traceback

import constants
import flags
from logger import logger, rpc_logger
import oracle as oracle_module
import test_plan as test_plan_module
import dashboard as dashboard_module


flags.set_usage('usage: %prog [options] test_plan')
flags.set_version('dioxide %s' % constants.VERSION)

flags.add_option('--interval', '-i', type='float', default=300)
flags.add_option('--dry-run', '-n', action='store_true')
flags.add_option('--port', '-p', type='int', default=8000)
flags.add_option('--no-show-plan', '--nosp', action='store_false',
                 dest='show_plan', default=True)
flags.add_option('--verbose', '-v', action='count', default=0)
flags.add_option('--quiet', '-q', action='count', default=0)
flags.add_option('--max-log-size-in-mb', '-s', type='float', default=128)
flags.add_option('--disable-signal-handlers', '--dsh', action='store_true')
flags.add_option('--inspector', '-c')


def install_signal_handlers(signal_handler):
  signal.signal(signal.SIGHUP, signal_handler)
  signal.signal(signal.SIGINT, signal_handler)
  signal.signal(signal.SIGQUIT, signal_handler)
  signal.signal(signal.SIGTERM, signal_handler)


def setup_logger(test_plan):
  log_file = test_plan.name.lower().replace(' ', '_')
  quiet = flags.get_option('quiet', 0)
  verbose = flags.get_option('verbose', 0)
  max_log_size_in_mb = flags.get_option('max_log_size_in_mb', 128)
  level = logger.WARNING + quiet - verbose
  logger.setup('%s' % log_file, level, max_log_size_in_mb)
  rpc_level = logger.ERROR + quiet - verbose
  rpc_logger.setup('%s.rpc' % log_file, rpc_level, max_log_size_in_mb)


def main():
  parser, options, arguments = flags.parse_options()
  if not arguments:
    parser.error('missing test plan file')
  test_plans = test_plan_module.read_test_plans_from_file(arguments[0])
  if not test_plans:
    parser.error('missing test plan definition in %r' % arguments[0])
  test_plan = test_plans[0]

  setup_logger(test_plan)

  oracle = oracle_module.Oracle(test_plan, flags.get_option('inspector'))
  oracle.setup()

  if flags.get_option('show_plan', True):
    logger.error(test_plan.pformat(include_tests=True, include_hosts=True))

  change_notifier = threading.Event()
  port = flags.get_option('port', 8000)
  if port:
    dashboard = dashboard_module.Dashboard(oracle, change_notifier.set)
    dashboard.setup()
    dashboard.start(port)

  signals_caught = []
  if not flags.get_option('disable_signal_handlers'):

    def signal_handler(signum, frame):
      if signum != signal.SIGHUP:
        signals_caught.append((signum, frame, time.time()))
      change_notifier.set()

    install_signal_handlers(signal_handler)

  iteration = 0
  while not signals_caught:
    print
    logger.error('Starting iteration %d ...' % iteration)
    try:
      oracle.run_once(schedule_only=iteration == 0,
                      dry_run=flags.get_option('dry_run'))
    except _mysql_exceptions:
      logger.error('Caught _mysql_exceptions from main loop\n%s' %
                   traceback.format_exc())
    if signals_caught:
      break
    interval = flags.get_option('interval', 300)
    logger.error('Sleeping for %g seconds ...' % interval)
    change_notifier.clear()
    change_notifier.wait(interval)
    if change_notifier.isSet():
      logger.error('Wake up early')
    iteration += 1

  print
  logger.error('Exit')


if __name__ == '__main__':
  main()
